package io.sphere.sdk.queries;
import io.sphere.sdk.client.SphereClient;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.stream.Collectors;
import java.util.stream.LongStream;
import static java.util.concurrent.CompletableFuture.completedFuture;
import static java.util.stream.Collectors.toList;
public class QueryAll<T, C extends QueryDsl<T, C>> {
private static final int DEFAULT_PAGE_SIZE = 500;
private final QueryDsl<T, C> baseQuery;
private final long pageSize;
private QueryAll(final QueryDsl<T, C> baseQuery, final long pageSize) {
this.baseQuery = baseQuery;
this.pageSize = pageSize;
}
public CompletionStage<List<T>> run(final SphereClient client) {
return queryPage(client, 0).thenCompose(result -> {
final List<CompletableFuture<List<T>>> futureResults = new ArrayList<>();
futureResults.add(completedFuture(result.getResults()));
futureResults.addAll(queryNextPages(client, result.getTotal()));
return transformListOfFuturesToFutureOfLists(futureResults);
});
}
private List<CompletableFuture<List<T>>> queryNextPages(final SphereClient client, final long totalElements) {
final long totalPages = totalElements / pageSize;
return LongStream.rangeClosed(1, totalPages)
.mapToObj(page -> queryPage(client, page)
.thenApply(PagedQueryResult::getResults)
.toCompletableFuture())
.collect(toList());
}
private CompletionStage<PagedQueryResult<T>> queryPage(final SphereClient client, final long pageNumber) {
final QueryDsl<T, C> query = baseQuery
.withOffset(pageNumber * pageSize)
.withLimit(pageSize);
return client.execute(query);
}
private CompletableFuture<List<T>> transformListOfFuturesToFutureOfLists(final List<CompletableFuture<List<T>>> futures) {
final CompletableFuture[] futuresAsArray = futures.toArray(new CompletableFuture[futures.size()]);
return CompletableFuture.allOf(futuresAsArray)
.thenApply(x -> futures.stream()
.map(CompletableFuture::join)
.flatMap(Collection::stream)
.collect(Collectors.<T>toList()));
}
public static <T, C extends QueryDsl<T, C>> QueryAll<T, C> of(final QueryDsl<T, C> baseQuery) {
return of(baseQuery, DEFAULT_PAGE_SIZE);
}
public static <T, C extends QueryDsl<T, C>> QueryAll<T, C> of(final QueryDsl<T, C> baseQuery, final int pageSize) {
return new QueryAll<>(baseQuery, pageSize);
}
}